package znet

import (
	"errors"
	"fmt"
	"io"
	"net"
	"sync"
	"zinx/Zinx/utils"
	"zinx/Zinx/ziface"
)

// IConnection接口实现, 定义一个Connection连接模块
type Connection struct {
	TcpServer     ziface.IServer         // 当前连接的服务器模块
	Conn          *net.TCPConn           // 当前连接的socket(TCP套接字)
	ConnID        uint32                 // 当前连接的ID
	IsClosed      bool                   // 当前连接的状态
	RouterHandler ziface.IRouterHandler  // 当前连接的路由管理
	ExitChan      chan bool              // 告知当前连接停止 channel
	MsgChan       chan []byte            // 读写分离-通信 无缓存channel
	Property      map[string]interface{} // 自定义连接属性集合
	PropertyLock  sync.RWMutex           // 自定义连接属性读写锁
}

// 初始化连接
func NewConnection(server ziface.IServer, conn *net.TCPConn, connID uint32, routerHandler ziface.IRouterHandler) *Connection {
	c := &Connection{
		TcpServer:     server,
		Conn:          conn,
		ConnID:        connID,
		IsClosed:      false,
		RouterHandler: routerHandler,
		ExitChan:      make(chan bool, 1),
		MsgChan:       make(chan []byte),
		Property:      make(map[string]interface{}),
	}
	// 连接管理中添加连接
	c.TcpServer.GetConnManager().AddConn(c)
	return c
}

// 读取(拆包)数据
func (c *Connection) StartReader() {
	fmt.Println("[Connection]StartReader().. ConnID = ", c.ConnID)
	defer fmt.Println("[Connection]Reader exit", "ConnID: ", c.ConnID, c.RemoteAddr().String())
	defer c.Stop() // break时调用
	for {
		// --------拆包--------
		// 定义数据包对象
		dp := NewDataPack()
		// 读取客户端发送的数据包Head
		binaryHead := make([]byte, dp.GetHeadLen())
		if _, err := io.ReadFull(c.GetTCPConnection(), binaryHead); err != nil {
			fmt.Println("[Read Msg Head]err:", err)
			break
		}
		// 拆包 得到ID, DataLen放在msg对象中
		msg, err := dp.Unpack(binaryHead)
		if err != nil {
			fmt.Println("[Unpack Msg Head]err:", err)
			break
		}

		// 根据msg.DataLen再次读取数据包获取msg.Data
		var data []byte
		if msg.GetDataLen() > 0 {
			data = make([]byte, msg.GetDataLen())
			if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil {
				fmt.Println("[Read Msg Data]err:", err)
				break
			}
		}
		msg.SetData(data)
		// --------拆包--------
		// 得到当前连接的请求(Request)
		req := Request{
			Conn: c,
			Msg:  msg,
		}
		// 判断是否开启工作池, 并执行ID对应的路由方法
		if utils.Global.WorkerPoolSize > 0 {
			// 将请求添加到消息队列处理
			c.RouterHandler.SendMsgToTaskQueue(&req)
		} else {
			// 直接执行请求对应的路由
			go c.RouterHandler.DoRouterHandler(&req)
		}
	}
}

// 数据TLV封包->Writer
func (c *Connection) SendMsg(id uint32, data []byte) error {
	// 判断连接是否关闭
	if c.IsClosed {
		return errors.New("[Connection is closed]")
	}
	// --------封包--------
	// 定义数据包对象
	dp := NewDataPack()
	// 封包
	binaryPack, err := dp.Pack(NewMessage(id, data))
	if err != nil {
		return errors.New(fmt.Sprintln("Msg id:", id, "[SendMsg Pack]err:", err))
	}
	// --------封包--------
	// 发送数据包给StartWriter()
	c.MsgChan <- binaryPack
	return nil
}

// 写入数据
func (c *Connection) StartWriter() {
	fmt.Println("[Connection]StartWriter().. ConnID = ", c.ConnID)
	defer fmt.Println("[Connection]Writer exit", "ConnID: ", c.ConnID, c.RemoteAddr().String())
	// 循环-阻塞等待MsgChan, 并写入客户端
	for {
		select {
		case data := <-c.MsgChan:
			if _, err := c.Conn.Write(data); err != nil {
				fmt.Println("[Connection]Write err:", err)
				return
			}
			//Reader已退出, Writer也要退出
		case <-c.ExitChan:
			return
		}
	}
}

// 启动连接
func (c *Connection) Start() {
	fmt.Println("[Connection]Start().. ConnID = ", c.ConnID)
	// 读写分离模型
	// Start->go Reader && go Writer
	// Reader->Request->[Handler]->SendMsg->Writer
	// 读数据
	go c.StartReader()
	// 写数据
	go c.StartWriter()
	// 调用启动连接后的Hook
	c.TcpServer.CallOnConnStart(c)
}

// 停止连接
func (c *Connection) Stop() {
	fmt.Println("[Connection]Stop().. ConnID = ", c.ConnID)
	// 判断当前连接是否已关闭
	if c.IsClosed {
		return
	}
	c.IsClosed = true
	// 调用关闭连接前的Hook
	c.TcpServer.CallOnConnStop(c)
	// 关闭连接
	c.Conn.Close()
	// 关闭Writer
	c.ExitChan <- true
	// 连接管理中删除连接
	c.TcpServer.GetConnManager().RemoveConn(c)
	// 回收资源
	close(c.ExitChan)
	close(c.MsgChan)
}

// 获取当前连接的套接字(socket/conn)
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

// 获取当前连接ID
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

// 获取远程客户端地址信息
func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

// ----自定义连接属性集合----
// 设置属性
func (c *Connection) SetProperty(key string, value interface{}) {
	// 保护共享资源map, 写map时需要上写锁
	c.PropertyLock.Lock()
	defer c.PropertyLock.Unlock()
	c.Property[key] = value
}

// 返回属性
func (c *Connection) GetProperty(key string) (interface{}, error) {
	// 保护共享资源map, 读map时需要上读锁
	c.PropertyLock.RLock()
	defer c.PropertyLock.RUnlock()
	if value, ok := c.Property[key]; ok {
		return value, nil
	} else {
		return nil, errors.New(fmt.Sprintln("[Connection]Get fail, Property not FOUND"))
	}
}

// 删除属性
func (c *Connection) RemoveProperty(key string) {
	// 保护共享资源map, 写map时需要上写锁
	c.PropertyLock.Lock()
	defer c.PropertyLock.Unlock()
	delete(c.Property, key)
}
